﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Index;

namespace Lucandra.Net
{
    internal class LucandraTermDocs : TermDocs
    {
        protected Term currentTerm;
        protected LucandraTermInfo.LucandraTermInfoDocument[] termDocuments;
        protected int documentPosition;
        protected bool isClosed;

        protected LucandraReader @LucandraReader { get; private set; }

        public LucandraTermDocs(LucandraReader lucandraReader)
        {
            this.LucandraReader = lucandraReader;
            this.documentPosition = -1;
            this.OnDocumentPositionChanged();
            this.isClosed = false;
        }


        public void Seek(Term term)
        {
            // Search for the term info in the LucandraSearchContext cache, if a search context exists.  Otherwise,
            // pull the information from Cassandra.
            LucandraTermInfo termInfo = null;
            if (LucandraSearchContext.Current != null)
                termInfo = LucandraSearchContext.Current.GetTermInfo(term);

            if (termInfo == null)
            {
                var termEnum = new LucandraTermEnum(this.LucandraReader, term, 1);
                //var termReader = new TermInfoReader(this.LucandraReader.Client, this.LucandraReader.IndexName, 1);
                //termReader.PositionAt(term);

                if (termEnum.CurrentTerm != null && termEnum.CurrentTerm.Equals(term))
                {
                    var termInfoDocuments = termEnum.GetTermInfoDocuments();
                    this.termDocuments = (termInfoDocuments == null ? null : termInfoDocuments.ToArray());
                }
                else
                    this.termDocuments = null;
            }
            else
                this.termDocuments = termInfo.Documents.ToArray();

            if (this.termDocuments != null)
                this.currentTerm = term;

            this.documentPosition = -1;
            this.OnDocumentPositionChanged();
            this.isClosed = false;
        }

        public void Seek(TermEnum termEnum)
        {
            var lucandraTermEnum = termEnum as LucandraTermEnum;
            this.termDocuments = lucandraTermEnum.GetTermInfoDocuments().ToArray();
            this.documentPosition = -1;
            this.OnDocumentPositionChanged();
            this.isClosed = false;
            this.currentTerm = lucandraTermEnum.CurrentTerm;
        }

        public int Doc()
        {
            if (this.documentPosition == -1)
            {
                this.OnDocumentPositionChanged();
                this.documentPosition = 0;
            }

            string documentID = this.termDocuments[this.documentPosition].DocumentID;
            //return this.LucandraReader.GetDocumentNumberFromDocumentID(documentID);
            return this.LucandraReader.AddDocumentMapping(this.termDocuments[this.documentPosition], this.currentTerm.Field());
        }

        public int Freq()
        {
            if (this.documentPosition == -1)
            {
                this.OnDocumentPositionChanged();
                this.documentPosition = 0;
            }

            return this.termDocuments[this.documentPosition].Frequency;
        }

        public bool Next()
        {
            if (this.termDocuments == null || this.documentPosition == this.termDocuments.Length - 1)
            {
                this.isClosed = true;
                return false;
            }

            this.documentPosition++;
            this.OnDocumentPositionChanged();
            return true;
        }

        public int Read(int[] docs, int[] freqs)
        {
            if (this.isClosed)
                return 0;

            int i = 0;
            for (; this.termDocuments != null && this.documentPosition < this.termDocuments.Length && this.termDocuments.Length != 0 && i < docs.Length; i++)
            {
                docs[i] = this.Doc();
                freqs[i] = this.Freq();
                if (!this.Next())
                {
                    i++;
                    break;
                }
            }

            return i;
        }

        public bool SkipTo(int target)
        {
            while (target > this.Doc())
            {
                if (!this.Next())
                    return false;
            }

            return true;
        }

        public void Close()
        {
            this.termDocuments = null;
            this.documentPosition = -1;
            this.OnDocumentPositionChanged();

            this.LucandraReader = null;
        }

        protected virtual void OnDocumentPositionChanged()
        {
        }
    }
}
